import logging
import threading
import time
from datetime import datetime

from scheduler.cron import Cron

logger = logging.getLogger(__name__)


def scheduler(cron, retry_times=3, retry_interval=5):
    scheduler_cron = Cron(cron)

    def schedule_internal(func):

        def wrapper(execute_datetime):
            try:
                next_now = datetime.now()
                next_execution_datetime = next(execute_datetime)
                if next_execution_datetime > next_now:
                    next_interval = (next_execution_datetime - next_now).seconds + 1
                    kwargs = {"execute_datetime": execute_datetime}
                    threading.Timer(interval=next_interval, function=wrapper, kwargs=kwargs).start()
            except StopIteration:
                pass

            execute_times = 0
            while execute_times <= retry_times:
                try:
                    logger.debug("start to execute the task %s" % (func))
                    func()
                    logger.debug("finish to execute the task %s" % (func))
                except Exception as e:
                    logger.error("it is failure to execute the task %s, the error is %s" % (func, str(e)))
                    if execute_times < retry_times:
                        time.sleep(retry_interval)
                    execute_times += 1
                else:
                    break

        execute_datetime = scheduler_cron.next_execute_time()
        try:
            next_execution_datetime = next(execute_datetime)
            while next_execution_datetime <= datetime.now():
                next_execution_datetime = next(execute_datetime)
            interval = (next_execution_datetime - datetime.now()).seconds + 1
            kwargs = {"execute_datetime": execute_datetime}
            threading.Timer(interval=interval, function=wrapper, kwargs=kwargs).start()
            return wrapper
        except StopIteration:
            pass

    return schedule_internal
